﻿using System;
using System.Linq;
using EnterpriseLibraryExtensions.Events.Aggregation;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace Events.PolicyInjection
{
	public class EventAggregationCallHandler : ICallHandler
	{
		private readonly EventAggregationMode _eventAggregationMode;
		private readonly IScopeOptions _scopeOptions;

		public EventAggregationCallHandler()
			: this(typeof(NoFilteringOptions), EventAggregationMode.Required)
		{
		}

		public EventAggregationCallHandler(EventAggregationMode eventAggregationMode)
			: this(typeof(NoFilteringOptions), eventAggregationMode)
		{
		}

		public EventAggregationCallHandler(Type scopeOptionsType)
			: this(scopeOptionsType, EventAggregationMode.Required)
		{
		}

		public EventAggregationCallHandler(Type scopeOptionsType, EventAggregationMode eventAggregationMode)
		{
			if (scopeOptionsType == null)
			{
				throw new ArgumentNullException("scopeOptionsType");
			}

			if (!scopeOptionsType.GetInterfaces().Any(i => i == typeof(IScopeOptions)))
			{
				throw new ArgumentException(@"scopeOptionsType must expose IScopeOptions interface", "scopeOptionsType");
			}

			_scopeOptions = (IScopeOptions)Activator.CreateInstance(scopeOptionsType);

			_eventAggregationMode = eventAggregationMode;
		}

		public int Order { get; set; }

		public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}

			if (getNext == null)
			{
				throw new ArgumentNullException("getNext");
			}

			IMethodReturn nextResult = null;

			using (var scope = new EventAggregationScope(_eventAggregationMode) { Options = _scopeOptions })
			{
				nextResult = getNext().Invoke(input, getNext);

				scope.Complete();
			}

			return nextResult;
		}
	}
}
